#include <iostream>
#include <memory>

namespace myPointers
{
	// unique_ptr给出的解决方案是禁用拷贝构造和赋值运算符重载
	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr):
			_ptr(ptr)
		{}
		~unique_ptr()
		{
			delete _ptr;
		}
		unique_ptr(const unique_ptr<T>& up) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
		T& operator*()
		{
			return *this;
		}
		T* operator->()
		{
			return this;
		}
	private:
		T* _ptr;
	};
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr):
			_ptr(ptr),
			_pCount(new int(1))
		{}
		shared_ptr(const shared_ptr<T>& sp):
			_ptr(sp._ptr),
			_pCount(sp._pCount)
		{}
		void release()
		{
			if (_pCount && --(*_pCount) == 0)
			{
				delete _ptr;
				delete _pCount;
			}
		}
		~shared_ptr()
		{
			release();
		}
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();
				_ptr = sp._ptr;
				_pCount = sp._pCount;
				(*_pCount)++;
			}
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
		void use_count()
		{
			std::cout << *_pCount << std::endl;
		}
	private:
		T* _ptr;
		int* _pCount;
	};
}
struct s1
{
	int a = 2;
	int b = 3;
};
struct ListNode
{
	int _val;
	myPointers::shared_ptr<ListNode> _prev;
	myPointers::shared_ptr<ListNode> _next;
	ListNode(int val):
		_val(val),
		_prev(nullptr),
		_next(nullptr)
	{}
	~ListNode()
	{
		std::cout << "~ListNode" << std::endl;
	}
};
void test_unique_ptr()
{
	myPointers::unique_ptr<int> p1(new int(1));
	// 由于我们禁用了拷贝构造函数和赋值运算符重载，不同的指针之间禁止相互赋值
	// 也算是解决了智能指针重复析构的问题
	/*auto p2 = p1;
	auto p3(p1);*/
}
// 实现RAII机制，并且能够像使用指针一样使用智能指针对象
void test_shared_ptr1()
{
	myPointers::shared_ptr<int> p1(new int(1));
	std::cout << *p1 << std::endl;
	auto p2(p1);
	std::cout << *p2 << std::endl;

	myPointers::shared_ptr<s1> p3(new s1);
	std::cout << p3->a << std::endl;
	std::cout << p3->b << std::endl;
}
// shared_ptr的循环引用问题
void test_shared_ptr2()
{
	myPointers::shared_ptr<ListNode> p1(new ListNode(1));
	myPointers::shared_ptr<ListNode> p2(new ListNode(2));
	p1.use_count();
	p2.use_count();

	// 由于循环引用问题，导致不能够正确析构，造成内存泄漏
	// 这个过程是什么样的？
	// 当函数结束后，p2先调用析构函数，引用计数减为1，然后p1调用析构函数，引用计数也减为1
	// 然后问题就来了：p1->next要等节点1生命周期结束时才析构，将引用计数减为0，此时才能结束节点2的生命周期
	// 而p2->prev要等待节点2生命周期结束后才析构，将引用计数减为0，此时才能结束节点1的生命周期
	// 这就陷入了循环等待的死循环！
	p1->_next = p2;
	p2->_prev = p1;
	
}

// int main()
// {
// 	//test_shared_ptr1();
// 	test_shared_ptr2();
// 	return 0;
// }